

//#include "data.h"
#include "myparser.h"



#define NCHAR 1000
#define MAXCHAR 20
#define NOR   139	    	// 139 # max of "OR" for all rules 
#define NRULES 7

#define N 3
#define T -1
#define F 0
#define boolean int

class parser parser;


/******************************************************************
        Dichiarazione delle variabili esterne al file.
******************************************************************/
extern int flip(double prob);

void concatena ( char *out, char *buffer1,  char *buffer2, char *buffer3 );
void compress(char *v1, int num, int diff);
void comprimi(char *v1, int num);

int interprete(char expression[], double vector[]);
bool matching(char *exp, double vector[], int &);

// E' una variabile globale che conta i predicati metchati dalla formula
static int match_preds;





void converti_stringa (char expression[], char binario[], double vector[]);
void evaluate (char stringa[]);
int valuta ( char expression[], double vector[]);
int valuta2 ( char expression[], double vector[]);
int valuta_espressione (char funct, int op1, int op2);
double controllo (char expression[], double vector[]);
int trova_clausola (char expression[], int i);
int conta_clausole (char expression[]);

void assign_vals(char expression[], double vector[]);


int interprete (char expression[], double vector[])
{
     
	char binario[NCHAR];
	int app;

	binario[0] = '\0';
	
	converti_stringa(expression, binario, vector);
	evaluate(binario);

	app = binario[0] - '0';
     
     
	return (app);
}

void converti_stringa (char expression[], char binario[], double vector[])
/* questa funzione converte la stringa prototipo in una stringa di bit e funzioni binarie
	partendo dal prototipo e dal sample	*/
{
	int bit=0;
	int i,j,k,lim1,lim2,len,diff;
	char rule[200];

	 

	len = strlen(expression);
	if(len >= NCHAR) {
		printf("regola errata in converti_stringa: len > NCHAR\n");
		printf("%s\n", expression);
		exit(1); 
	}

	for (j = 0; j <= len; j++)
		binario[j] = expression[j];

	j = 0;
	while ((binario[j] != '\0') && (j <= len )) {

		if (binario[j] == 'a') {
			lim1 = j-1;
			while ((binario[j] != ']') && (j <= len))
				j++;
			if (binario[j] == ']')             /* ho trovato una regola */
				lim2 = j;
			else {
				printf("regola errata in converti_stringa: manca ]\n");
				printf("%s\n", expression);
				exit(1); 							  /* regola errata !!*/
			}
			
			k = 0;
			for (i = lim1+1; i < lim2; i++) {       /* la copio nella stringa rule */
				rule[k] = binario[i];
				k++;
			}
			rule[k] = '\0';

			diff = lim2 - lim1;
			for(i = lim2; i <= len; i++)            /* la elimino da binario */
				binario[i-diff] = binario[i];
			len = strlen(binario);             /* aggiorno la lung. di binario */

			bit = valuta2(rule, vector);    /* ho cambiato il prototipo di valuta !! */
			binario[lim1] = bit+'0';
			j = lim1;
		}
		j++;
	} /*	end while + esterno		*/
}

int valuta( char expression[], double vector[])
/*	confrontando sample e expression di partenza restituisce 1 se c'e' compatibilita', 0 altrimenti	*/
{
	char operatore1, operatore2=' ';
	int  i=0,len,lim=4,k;          /* lim e' legata al num. max. di cifre relative agli indice delle features */

	int arco;
	double appoggio, valore, delta;
	int finale, flag;

	len = strlen(expression);
	if (expression[i] == 'a')
		i++;
	else {
        	printf("regola errata in valuta: non inizia con a \n");
		printf("%s\n", expression);
                exit(1);                                                          /* regola errata !!*/
        }

	while ( isdigit(expression[i]) && (i < len) )
		i++;

	if ( (i == 1) || (i > lim) ) {
        	printf("regola errata in converti_stringa: num feature errato\n");
		printf("%s\n", expression);
                exit(1);                                                          /* regola errata !!*/
        }

	arco = expression[1] -'0';
	for (k = 2; k < i; k++)
		arco = arco*10 + expression[k]-'0';

	operatore1 = expression[i++];
	if( (operatore1 != '>') && (operatore1 != '=') && (operatore1 != '<') &&
        (operatore2 != '>') ) {
		printf("regola errata in valuta: op errato\n");
		printf("%s\n", expression);
                exit(1);                                                          /* regola errata !!*/
        }

	if ( !isdigit(expression[i]) )
	  // Si controlla se c'e' il doppio operatore di confronto: "<=" oppure ">="
      if ((expression[i] == '=') || (expression[i] == '>'))  
		operatore2 = expression[i++];
		 /* if( operatore2 != '=') {
			printf("regola errata in valuta: op 2 errato\n");
			printf("%s\n", expression);
                	exit(1);                                                            regola errata !!
        	} 

	} */
	// if( (i == len-1) && isdigit(expression[i]) )
		valore = atof(&expression[i]); //expression[i] - '0';
/*	else {
		printf("regola errata in valuta: manca occorrenza\n");
		printf("%s\n", expression);
                exit(1);                                                          /* regola errata !!
        } */

   /* if (vector[arco] == NULL_VALUE)
   if (vector[arco] == 0.0)
      return 0; 
     */ 

	appoggio = vector[arco];
    // cout<<endl<<"appoggio: "<<appoggio<<" arco: "<<arco;
	switch (operatore1) {
	case '>':
		if ( operatore2 == '=') {
			if ( appoggio >= valore  )
				finale=1;
			else
				finale=0;
		}
		else if (appoggio > valore)
				finale=1;
		else
				finale=0;
		break;
	case '<':
		if ( operatore2 == '=') {
			if ( appoggio <= valore)
				finale=1;
			else
				finale=0;
		}
		else if (operatore2 == '>')
		     {
		       // Si trova il delta all'interno dell'espressione.
               while (expression[i++] != ',')
                 ; 
               // Si aqcquisisce il valore della delta      
               delta = atof(&expression[i]);
             //  cout<<" val: "<<valore<<" delta: "<<delta;;
		       if((appoggio > valore - delta) && (appoggio < valore + delta))
                 finale = 1;
               else finale = 0;   // cout<<" "<<finale;     
             //  cout<<" valore: "<<valore<<" delta: "<<delta<<" finale: "<<finale;
             }
		else if (appoggio < valore)
				finale=1;
		else
				finale=0; //cout<<endl<<operatore1<<" "<<operatore2;
		break;
	case '=':
		if (appoggio == valore)
			finale=1;
		else 
			finale=0;
		break;
	}

	
    // Si incrementa il numero di predicati metchati.
    if (finale)
	  ++match_preds;
 
    return (finale);
}

void evaluate (char stringa[])
/*	questa funzione valuta il valore della stinga binaria in ingresso	*/
/*	utilizzando i risultati delle operazioni tra bit ed operatori binari	*/
{
	int punt1,punt2;
	int app1, app2;
	char funct;
	int j,i;
	
	char p[NCHAR];
	char bit[N];
	char testa[NCHAR]; 
	char coda[NCHAR];


	punt1 = 0; punt2 = 0; 
	testa[0] = '\0'; 
	coda[0] = '\0'; 
	bit[0] = '\0';
	/*printf ("la stringa passata vale %s\n",stringa);
	printf ("la sua lunghezza e' %d\n", strlen(stringa));*/
	while (strlen(stringa) > 1) {
		/*printf("la lunghezza della stringa e' pari a %d\n", strlen(stringa));
		printf ("quindi entriamo nel ciclo\n");
		getchar();*/
		while (!isdigit(stringa[punt1]))
			punt1++;
		
		app1 = stringa[punt1]-'0';
		/*printf ("app1 vale %d \n", app1);
		printf ("punt1 vale %d\n", punt1);
		getchar();*/

		while (stringa[punt1-1] == '!')		/* ciclo di controllo per eliminare le not */
		{
			/*printf ("abbiamo trovato una not precedente app1\n");*/
			app1 = !app1;
			stringa[punt1]=app1+'0';
			comprimi(stringa,punt1-1);
			/*printf("dobbiamo complementare app1\n");
			printf("app1 vale %d\n", app1);
			getchar();*/
			punt1--;
		}
		
		punt1++;
		funct = stringa[punt1];
		if ((funct == ']') && (stringa[punt1-2] == '[')) {
			if (stringa[punt1+1]=='\0')
				stringa[punt1]='\0';
			else
				comprimi(stringa,punt1);
				
			comprimi(stringa, punt1-2);
			/*printf("la stringa vale %s\n", stringa);
			getchar();*/
			punt1=0;
		}
		else {
			/*printf("funzione vale %c\n", funct);
			getchar();*/
			punt1++;
			while (stringa[punt1]=='!')
				punt1++;
			if (isdigit(stringa[punt1])) {
				app2 = stringa[punt1]-'0';
				/*printf ("app2 vale %d\n", app2);
				printf ("punt1 vale %d\n", punt1);
				getchar();*/

				while (stringa[punt1-1]=='!') {		/* ciclo di controllo per eliminare le not */
					app2=!app2;
					stringa[punt1]=app2+'0';
					/*printf("dobbiamo complementare app2\n");
					printf("app2 vale %d\n", app2);
					getchar();*/
					comprimi(stringa,punt1-1);
					punt1--;
				}
				bit[0]=valuta_espressione(funct, app1, app2)+'0';
				bit[1]='\0';
				/*printf("bit vale %c\n",bit[0]);
				getchar();*/
				punt2=punt1+1;
				if ((unsigned)punt2>=strlen(stringa))
					punt2=strlen(stringa)-1;

				/*printf("punt2 vale %d e punta a %c\n",punt2, stringa[punt2]);
				getchar();*/
				punt1=punt1-4;	/* di fatto porto il puntatore prima della parentesi di apertura del nodo */
				/*printf("punt1 vale %d e punta a %c\n",punt1, stringa[punt1]);
				getchar();*/
			
				if ((stringa[punt2]==']')||((unsigned)punt2>=strlen(stringa)-1)) {
					if (punt1<0) {
						punt1=0;
						testa[0]='\0';
						/*printf("la testa della stringa e' vuota\n");
						getchar();*/
					}
					else {
						for (i=0; i<=punt1; i++)		
							testa[i]=stringa[i];
						testa[i]='\0';
						/*printf ("la testa della stringa vale %s\n", testa);
						getchar();*/
					}
			
					if ((unsigned)punt2>=strlen(stringa)-1) {
						coda[0]='\0';
						/*printf("la coda e' vuota\n");*/
					}
					else {
						j=0;
						for (i=punt2+1;(unsigned) i<=strlen(stringa); i++, j++)
							coda[j]=stringa[i];
						/*printf ("la coda della stringa vale %s\n", coda);
						getchar();*/
					}
				}
				else {
					punt1+=1;
					if (punt1<0) {
						punt1=0;
						testa[0]='\0';
						/*printf("la testa della stringa e' vuota\n");
						getchar();*/
					}
					else {
						for (i=0; i<=punt1; i++)		
					
							testa[i]=stringa[i];
						
						testa[i]='\0';
						/*printf ("la testa della stringa vale' %s\n", testa);
						getchar();*/
					}

					if ((unsigned)punt2>=strlen(stringa)-1) {
						coda[0]='\0';
						/*printf("la coda e' vuota");*/
					}
					else {
						j=0;
						for (i=punt2; (unsigned)i<=strlen(stringa); i++, j++)
							coda[j]=stringa[i];
						/*printf ("la coda della stringa vale %s\n", coda);
						getchar();*/
					}
				
				}

				concatena(p,testa,bit,coda);

				for (i = 0; i <= strlen(p); i++)
					stringa[i] = p[i];
				stringa[i] ='\0';
				/*printf ("ora la stringa vale: %s\n", stringa);
				getchar();*/
				punt1 = 0;
			}
			else if ( !isdigit(stringa[punt1]) )
				punt1++;
		}
	} /*end while + esterno */
}

int valuta_espressione (char funct, int op1, int op2)
/* restituisce il risultato di operazioni tra bit */
{
	int m = -1;
	if( funct == '^' )
		m=op1 && op2;
	else if	(funct == 'v')
		m=op1 || op2;

	/*
	printf("l'espressione %d %c %d ha come risultato %d\n", op1, funct, op2, m );
	getchar();
	*/

	return (m);
}



void comprimi(char *v1, int num)
/*questa funzione elimina un elemento nel expression che gli viene passato e precisamente l'elemento num */
{
        int i;

        for (i= num;i<=strlen(v1); i++ )
                v1[i]= v1[i+1];

        return ;
}

void concatena ( char *out, char *buffer1,  char *buffer2, char *buffer3 )
{
	strcpy( out, buffer1);
	strcat ( out, buffer2);
	strcat ( out, buffer3);
} 


double controllo (char expression[], double vector[], int features_num)
// questa funzione serve ad introdurre quella successiva: trova clausola 
{
	int i, cl_tot, cl, tmp;
	double score;

	cl = cl_tot = 0;
	for (i = 0; i < features_num; i++) {
		if (vector[i] != 0) {
			cl_tot++;
			tmp = trova_clausola (expression, i);
			if (tmp == 1)
                        	cl++;
		}
	}

	if( cl == cl_tot )
		return( 1.0 );
	else {
		score = (double)cl / (double)cl_tot;
		return( score  );
	}
}

int trova_clausola (char expression[], int i)
/* questa funzione serve a controllare che gli archi con occorrenze !=0 
   nel sample siano menzionati nel prototipo */
{
	int j, arco, flag;

	arco = -1;
	j = 0;

	while ((arco != i) && (j<strlen(expression))) {
		while ((expression[j] != 'a') && (j<strlen(expression)))
			j++;
		if (j < strlen(expression)) {
			arco = expression[++j] - '0';
			j++;
			flag = 0;
			if (isdigit (expression[j])) {
				arco = arco * 10 + (expression[j] - '0');
				flag = 1;
			}
			j++;
			if ((isdigit (expression[j])) && (flag = 1))
                                arco = arco * 10 + (expression[j] - '0');
		}
	}

	if (arco == i) 
		return 1;
	else 	
		return 0;
}


int conta_clausole (char expression[])
/* questa funzione mi permette di contare il numero delle clausole di cui � composto un expression */
{
	int i,conta;
	
	conta=0;
	i=0;
	/*printf ("il expression al vaglio e' %s\n", expression);
	printf("troviamo il numero delle sue clausole\n");
	getchar();*/
	while ((unsigned)i++<strlen(expression))
	  if (expression[i] == 'a')
	    conta++;
      	    
	/*
	{
		
		while ((expression[i]!='a')&&((unsigned)i<strlen(expression)))
		{
			i++;
			/*printf("il valore di i e' %d\n",i);
			getchar();
		}
		if ((expression[i]=='a')&&((unsigned)i<strlen(expression)))
		{	conta += 1;
			/*printf("il numero parziale di clausole trovate e' %d\n", conta);
		
			getchar(); 
			i++;
			/*printf("il valore di i e' %d\n", i);
			getchar();
		}
	}*/

	return (conta);
}


  /* ******************************************************************** *
   * ******************************************************************** *
   * ******************************************************************** *
   
     La parte di codice che segue e' stata ideata e scritta da FRANCESCO 
     FONTANELLA a partire dal:        15 Luglio 2003.

   * ******************************************************************** *
   * ******************************************************************** *
   * ******************************************************************** *
   */


  /*
  ----------------- procedura matching ---------------------------------------
  *** Scritta il: 15/07/03
  Restituisce true se l'espressione passata come primo parametro (exp) met-
  cha completamente il sample passato come secondo parametro (sample), fal-
  se altrimenti.
  *** Ultima modifica:
  */ 
  bool matching(char *exp, double vector[], int &preds_counter)
  {
      int inter;  
      
      
      // Si inizializza il numero di predicati metchati.
      match_preds = 0;
      
      
      /* Si chiama la funzione che controlla se l'espressione metcha l'in-
         viduo. */
      inter = interprete (exp, vector);

      // Si restituisce il risultato ottenuto dall'interprete.
      if (inter == 1)
      {
	    preds_counter = match_preds;
	   
        return true;
      }    
      else 
      {
          // Se non c'� matching si annulla il numero di predicati metchati.
          preds_counter = 0;
	             
          return false;
      }    
  }	

/*
  ----------------- procedura matching ---------------------------------------
  *** Scritta il: 15/07/03
  Restituisce true se l'espressione passata come primo parametro (exp) met-
  cha completamente il sample passato come secondo parametro (sample), fal-
  se altrimenti.
  *** Ultima modifica:
  */ 
 

int valuta2( char expression[], double vector[])
/*	confrontando sample e expression di partenza restituisce 1 se c'e' compatibilita', 0 altrimenti	*/
{
	char operatore1, operatore2=' ';
	int  i=0,len,lim=4,k;          /* lim e' legata al num. max. di cifre relative agli indice delle features */

	int arco;
	double appoggio, valore, delta;
	int finale, flag;

    char tmp_exp[5*NCHAR];
      
    // Si copia l'espressione in input in una stringa temporanea.
    strcpy(tmp_exp, expression);
    
    // Si sostituiscono i simboli delle variabili con quelli contenuti nel vettore in input.
    assign_vals(tmp_exp, vector);
    
    // Si chiama il valutatore per calcolare il valore dell'espressione appena costruita.
    appoggio = parser.eval_exp(tmp_exp);
    //cout<<endl<<tmp_exp<<endl;
    
    
    i=0; 
    while ((tmp_exp[i] != '<') && (tmp_exp[i] != '>'))
      ++i;
    
 
	operatore1 = tmp_exp[i++];
	if( (operatore1 != '>') && (operatore1 != '=') && (operatore1 != '<') &&
        (operatore2 != '>') ) {
		printf("regola errata in valuta: op errato\n");
		printf("%s\n", expression);
                exit(1);                                                          /* regola errata !!*/
        }

	if ( !isdigit(expression[i]) )
	  // Si controlla se c'e' il doppio operatore di confronto: "<=" oppure ">="
      if (expression[i] == '=') 
		operatore2 = tmp_exp[i++];
		 /* if( operatore2 != '=') {
			printf("regola errata in valuta: op 2 errato\n");
			printf("%s\n", expression);
                	exit(1);                                                            regola errata !!
        	} 

	} */
	// if( (i == len-1) && isdigit(expression[i]) )
		valore = atof(&tmp_exp[i]); //expression[i] - '0';
/*	else {
		printf("regola errata in valuta: manca occorrenza\n");
		printf("%s\n", expression);
                exit(1);                                                          /* regola errata !!
        } */

   /* if (vector[arco] == NULL_VALUE)
   if (vector[arco] == 0.0)
      return 0; 
     */ 

	//appoggio = vector[arco];
    // cout<<endl<<"appoggio: "<<appoggio<<" arco: "<<arco;
	switch (operatore1) {
	case '>':
		if ( operatore2 == '=') {
			if ( appoggio >= valore  )
				finale=1;
			else
				finale=0;
		}
		else if (appoggio > valore)
				finale=1;
		else
				finale=0;
		break;
	case '<':
		if ( operatore2 == '=') {
			if ( appoggio <= valore)
				finale=1;
			else
				finale=0;
		}
		else if (operatore2 == '>')
		     {
		       // Si trova il delta all'interno dell'espressione.
               while (expression[i++] != ',')
                 ; 
               // Si aqcquisisce il valore della delta      
               delta = atof(&expression[i]);
             //  cout<<" val: "<<valore<<" delta: "<<delta;;
		       if((appoggio > valore - delta) && (appoggio < valore + delta))
                 finale = 1;
               else finale = 0;   // cout<<" "<<finale;     
             //  cout<<" valore: "<<valore<<" delta: "<<delta<<" finale: "<<finale;
             }
		else if (appoggio < valore)
				finale=1;
		else
				finale=0; //cout<<endl<<operatore1<<" "<<operatore2;
		break;
	case '=':
		if (appoggio == valore)
			finale=1;
		else 
			finale=0;
		break;
	}

	
    // Si incrementa il numero di predicati metchati.
    if (finale)
	  ++match_preds;
 
    return (finale);
}


/* ----------------- procedura dtos ---------------------------------------
  *** Scritta il: 30/11/03
  Questa piccola funzione copia il double che si trova nel secondo parame-
  tro (dbl) nel primo parametro (str). 
  *** Ultima modifica:
  */
void dtos(char str[], double dbl)
{
    sprintf(str, "%.3f", dbl);
    
    return;
     
}

/* ----------------- procedura assign_vals --------------------------------
  *** Scritta il: 30/11/03
  Questa funzione accetta come input una stringa che contiene un'espressione
  e un vettore. Nella stringa in input le variabili denotate dalla stringa
  "an" vengono sostituite dalla stringa che contiene il valore n-esimo del 
  vettore passato come input.  
  *** Ultima modifica:
  */
   void assign_vals(char expression[], double vector[])
  {
     char tmp_exp[NCHAR] = "";
     int i, j, index, val_len;
     char tmp_val[20];
     
     
     i=0; // indice di expression
     j=0; // indice di tmp_exp
     
     //cout<<endl<<i<<endl<<j<<endl;
     
     while ((expression[i] != '\0') && (i < NCHAR))
       if (expression[i] != 'a')
       { // cout<<expression[i];
           tmp_exp[j++] = expression[i++];
       }   
       else
       { //cout<<expression[i]<<endl;
         // Si punta all'indice di a
         ++i;
         // Si converte il valore della variabile
         index = atoi(&expression[i]);
         
         //cout<<endl<<index<<endl;
                  
         // Adesso si preleva il valore dal vettore
         // ATTENZIONE!: PROVA, manca il controllo sull'indice prelevato!          
          dtos(tmp_val, vector[index]);
          
          //cout<<endl<<tmp_val<<endl;
 
         // Si misura la lunghezza della stringa appena copiata.
         val_len = strlen(tmp_val);
        // cout<<endl<<val_len<<endl;
         
         /* Si inserisce la stringa che contiene il valore numerico in quel-
            la in costruzione. */
         strcat(&tmp_exp[j], tmp_val);
         //cout<<j<<"***"<<tmp_exp<<"***"<<endl;
         // Adesso si aggiornano gli indici di scorrimento delle 2 stringhe.
         
         // Si aggiorna l'indice della espressione sorgente.
         if (index < 10)
           ++i;
         else if (index < 100)
                i += 2;
              else i+= 3;
         
         // Si aggiorna l'indice dell'espressione in costruzione.
         j += val_len;         
       //  cout<<endl<<"i:"<<i<<" j:"<<j<<endl;  
       }
        
     
     // Adesso si copia la stringa costruita in quella data in input.
     strcpy(expression, tmp_exp);     
    
     
     return;      
  }




/*
string dtos(double dbl){
    char buf[BUFSIZ];
    sprintf(buf, "%lf", dbl);
    return buf;
} */

  

